package com.itheima.advice;

import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.exception.MyException;
import com.itheima.pojo.Operatelog;
import com.itheima.service.OperateLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class AroundAdvice {
    @Pointcut("execution(* com.itheima.controller.*.*(..))")
    public void productPointcut(){

    }

    @Reference
    private OperateLogService operateLogService;

    /**
     * AOP环绕通知
     * @param pjp
     */
    @Around("productPointcut()")
    public Object aroundException(ProceedingJoinPoint pjp){
        //获取request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //处理日志信息
        Operatelog log = new Operatelog();
        Signature signature = pjp.getSignature();
        //获取方法名
        log.setMethodName(signature.getName());
        //获取全路径类名
        Object target = pjp.getTarget();
        log.setFullyClassName(target.getClass().getName());
        //当前时间
        String operationTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        log.setOperationTime(operationTime);
        //获取操作人
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String username = user.getUsername();
        log.setExecuteUser(username);
        //获取IP
        String remoteHost = request.getRemoteHost();
        log.setExecuteIp(remoteHost);
        //获取访问URL
        String requestURI = request.getRequestURI();
        log.setRequestUrl(requestURI);
        String errorMessage =null;
        errorMessage = (String) request.getAttribute("errorMessage");
        if(errorMessage==null){
            errorMessage="";
        }
        //获取方法参数对象数组
        Object[] args = pjp.getArgs();
        if(args.length>=1){
            //方法参数类型
            String[] parameters=new String[args.length];
            // 操作人 操作时间 操作人IP 访问资源(url) 执行时长
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                //参数名
                String typeName = arg.getClass().getTypeName();
                parameters[i]=typeName;
            }
            log.setParameters(Arrays.toString(parameters));
        }
        try {
            long start = System.currentTimeMillis();
            Object proceed = pjp.proceed();
            long end = System.currentTimeMillis();
            //执行时间
            String excuteTime=String.valueOf(end-start);
            log.setLongtime(excuteTime);
            operateLogService.addLog(log);
            return proceed;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            //自定义异常处理器
            throw new MyException(errorMessage);
        }
    }
}
